package com.tools.web.filter;

import com.tools.common.container.OwnRows;
import com.tools.common.container.RowKit;
import com.tools.common.exception.ReflectionException;
import com.tools.common.object.Note;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;

/**
 * 要定义一个过滤器给
 * Spring 容器管理时
 * 一些常用配置项就在此处配置
 * */
@Note("要定义一个过滤器给Spring 容器管理时" +
        "一些常用配置项就在此处配置")
public class FilterSource {

    @Note("具体的过滤器实例")
    private Filter filter;

    @Note("该过滤器在什么顺序执行过滤，默认是第 1 层过滤")
    private int order = 0;

    @Note("过滤器的名称")
    private String name;

    @Note("是否自启")
    private boolean enable = true;

    @Note("什么时机执行拦截操作")
    private DispatcherType dispatcherTypes = DispatcherType.REQUEST;

    @Note("需要执行过滤的请求 URI")
    private String[] urlPatterns;

    @Note("初始化过滤器时，这里存一些自己需要的自定义参数")
    private Map<String, String> initParameter;


    public FilterSource() {}

    public static FilterSource of() {
        return new FilterSource();
    }

    /* ************************************************************************************************************
     *
     *      Getter / Setter
     *
     * ************************************************************************************************************
     * */

    public Filter getFilter() {
        if(filter == null) throw new NullPointerException("过滤器尚未初始化");
        return filter;
    }

    public void setFilter(Filter filter) {
        if(filter == null) throw new NullPointerException("不能设置 null 的过滤器");
        this.filter = filter;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        if(order < 0) throw new IllegalArgumentException("过滤器的执行顺序不能为负数");
        this.order = order;
    }

    public String getName() {
        if(name == null || name.isEmpty()) {
            this.name = private_getFilterDefaultName();
        }
        return name;
    }

    public void setName(String name) {
        if(name == null || name.isEmpty()) throw new IllegalArgumentException("过滤器的名称不能为空");
        this.name = name;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    public DispatcherType getDispatcherTypes() {
        return dispatcherTypes;
    }

    public void setDispatcherTypes(DispatcherType dispatcherTypes) {
        if(dispatcherTypes == null) throw new NullPointerException("不允许设置 null 的 DispatcherType");
        this.dispatcherTypes = dispatcherTypes;
    }

    public String[] getUrlPatterns() {
        if(urlPatterns == null || urlPatterns.length == 0) throw new IllegalArgumentException("拦截路径为空，请先设置拦截路径");
        return urlPatterns;
    }

    public void setUrlPatterns(String urlPattern) {
        this.urlPatterns = new String[] {urlPattern};
    }

    public void setUrlPatterns(String... urlPatterns) {
        if(urlPatterns == null || urlPatterns.length == 0) throw new IllegalArgumentException("请设置至少一个拦截路径");
        this.urlPatterns = urlPatterns;
    }

    public void setUrlPatterns(Collection<String> urlPatterns) {
        if(urlPatterns == null) throw new IllegalArgumentException("请设置至少一个拦截路径");
        int size = urlPatterns.size();
        if(size == 0) throw new IllegalArgumentException("请设置至少一个拦截路径");
        this.urlPatterns = new String[size];
        int index = 0;
        for (String pattern : urlPatterns) {
            if(index == size) return;
            this.urlPatterns[index] = pattern;
            index++;
        }
    }

    public void setUrlPatterns(OwnRows<String> urlPatterns) {
        if(urlPatterns != null) {
            int size = urlPatterns.size();
            if(size == 0) throw new IllegalArgumentException("请设置至少一个拦截路径");
            int index = 0;
            this.urlPatterns = new String[size];
            for (String pattern : urlPatterns) {
                if(index == size) return;
                this.urlPatterns[index] = pattern;
                index++;
            }
        }
        throw new IllegalArgumentException("请设置至少一个拦截路径");
    }


    public void setUrlPatterns(Iterable<String> urlPatterns) {
        if(urlPatterns == null) throw new IllegalArgumentException("请设置至少一个拦截路径");
        int size = RowKit.getIterableSize(urlPatterns);
        if(size == 0) throw new IllegalArgumentException("请设置至少一个拦截路径");
        this.urlPatterns = new String[size];
        int i = 0;
        for (String pattern : urlPatterns) {
            if(i < size) {
                this.urlPatterns[i] = pattern;
                i++;
            }
        }
    }

    public Map<String, String> getInitParameter() {
        return initParameter;
    }

    public void setInitParameter(Map<String, String> initParameter) {
        this.initParameter = initParameter;
    }


    @Override
    public String toString() {
        return "FilterSource{" +
                "filter=" + filter +
                ", order=" + order +
                ", name='" + name + '\'' +
                ", enable=" + enable +
                ", dispatcherTypes=" + dispatcherTypes +
                ", urlPatterns=" + Arrays.toString(urlPatterns) +
                ", initParameter=" + initParameter +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FilterSource that = (FilterSource) o;
        return order == that.order && enable == that.enable && Objects.equals(filter, that.filter) && Objects.equals(name, that.name) && dispatcherTypes == that.dispatcherTypes && Arrays.equals(urlPatterns, that.urlPatterns);
    }

    @Override
    public int hashCode() {
        int result = Objects.hash(filter, order, name, enable, dispatcherTypes);
        result = 31 * result + Arrays.hashCode(urlPatterns);
        return result;
    }

    /* ************************************************************************************************************
     *
     *      链式调用
     *
     * ************************************************************************************************************
     * */

    public FilterSource filter(Filter filter) {
        this.setFilter(filter);
        return this;
    }

    public FilterSource order(int order) {
        this.setOrder(order);
        return this;
    }

    public FilterSource name(String name) {
        this.setName(name);
        return this;
    }

    public FilterSource enable(boolean enable) {
        this.setEnable(enable);
        return this;
    }

    public FilterSource dispatcherTypes(DispatcherType dispatcherTypes) {
        this.setDispatcherTypes(dispatcherTypes);
        return this;
    }

    public FilterSource urlPatterns(String urlPattern) {
        this.setUrlPatterns(urlPattern);
        return this;
    }

    public FilterSource urlPatterns(String... urlPatterns) {
        this.setUrlPatterns(urlPatterns);
        return this;
    }

    public FilterSource urlPatterns(Collection<String> urlPatterns) {
        this.setUrlPatterns(urlPatterns);
        return this;
    }

    public FilterSource urlPatterns(OwnRows<String> urlPatterns) {
        this.setUrlPatterns(urlPatterns);
        return this;
    }

    public FilterSource urlPatterns(Iterable<String> urlPatterns) {
        this.setUrlPatterns(urlPatterns);
        return this;
    }

    public FilterSource initParameter(Map<String, String> initParameter) {
        this.setInitParameter(initParameter);
        return this;
    }

    /* ************************************************************************************************************
     *
     *      私有逻辑
     *
     * ************************************************************************************************************
     * */

    @Note("获取目标过滤器类的名称作为过滤器的默认名称")
    private static String private_getFilterDefaultName() {
        try {
            return FilterSource.class.getDeclaredField("filter").getName();
        } catch (NoSuchFieldException e) {
            throw new ReflectionException(e);
        }
    }
}
